# coding=utf8
__author__ = 'lijian'

from utils import byteUtil
import packet
import logging

_data_unit_size = {
    'afn_1': {
        'f1': 0,
        'f2': 0
    },
    'afn_4': {
        'f1': 4,
        'f2': 22,
        'f3': 24,
        'f4': 27,
        'f5': 5,
        'f6': 12,
        'f7': -1,
        'f9': -1,
        'f11': 7,
        'f12': 4,
        'f13': -1,
        'f17': -1,
        'f18': -1,
        'f19': -1,
        'f20': -1,
        'f25': -1,
        'f26': -1
    },
    'afn_5': {
        'f1': 2,
        'f2': 2,
        'f3': 2,
        'f9': 2,
        'f10': 1,
        'f11': 1,
        'f12': 9,
        'f13': 9,
        'f14': 1,
        'f15': 1,
        'f17':9,
        'f18':1,
        'f31': 6
    },
    'afn_a': {
        'f1': 0,
        'f2': 0,
        'f3': 0,
        'f4': 0,
        'f5': 0,
        'f6': 0,
        'f7': -1,
        'f9': -1,
        'f11': 0,
        'f12': 0,
        'f13': 0,
        'f17': -1,
        'f18': -1,
        'f19': 0,
        'f25': 2,
        'f26': 2
    },
    'afn_c': {
        'f2': 0,
        'f3': 0,
        'f4': 0,
        'f9': 0,
        'f10': 0,
        'f11': 2,
        'f12': 2,
        'f25': 0,
        'f33': 0,
        'f34': 0,
        'f35': 0,
        'f36': 0,
        'f37': 0,
        'f38': 0,
        'f39': 0
    },
    'afn_d': {
        'f17': 7,
        'f18': 7,
        'f19': 7,
        'f20': 7,
        'f21': 7,
        'f22': 7,
    },
    'afn_10':{
        'f9':122,
        'f10':0
    }
}


def enum(**enums):
    return type('Enum', (), enums)


class FrameDecode():
    STATE = enum(WAIT=1, LEN=2, DEP=3, ADDRESS=4, DATA=5, CRC=6, TAIL=7)

    def __init__(self):
        self.state = FrameDecode.STATE.WAIT
        self.frameRaw = []
        self.need=0

    def decode(self, data):
        if not data:
            return None, None

        start = 0
        while len(data[start:]) > 0:
            if self.state == FrameDecode.STATE.WAIT:
                byte = byteUtil.getByte(data[start:])
                if byte == 0x68:
                    self.frameRaw = []
                    self.frameRaw.append(byte)
                    self.state = FrameDecode.STATE.LEN
                start += 1

            elif self.state == FrameDecode.STATE.LEN:
                size, bytes = byteUtil.getBytes(data[start:], 4)
                self.frameRaw.extend(bytes)
                self.state = FrameDecode.STATE.DEP
                start += 4

            elif self.state == FrameDecode.STATE.DEP:
                byte = byteUtil.getByte(data[start:])
                if byte == 0x68:
                    self.frameRaw.append(byte)
                    self.state = FrameDecode.STATE.ADDRESS
                else:
                    self.state = FrameDecode.STATE.WAIT
                start += 1

            elif self.state == FrameDecode.STATE.ADDRESS:
                size, bytes = byteUtil.getBytes(data[start:], 8)
                self.frameRaw.extend(bytes)
                self.state = FrameDecode.STATE.DATA
                start += 8

                frameLen = byteUtil.decodeShort(self.frameRaw[1:3])
                dataRegionLen = frameLen - 8
                self.need=dataRegionLen

            elif self.state == FrameDecode.STATE.DATA:
                size, bytes = byteUtil.getBytes(data[start:], self.need)
                self.frameRaw.extend(bytes)

                if size==self.need:
                    self.state = FrameDecode.STATE.CRC
                    self.need=0
                else:
                    self.need=self.need-size

                start += size
            elif self.state == FrameDecode.STATE.CRC:
                size, bytes = byteUtil.getBytes(data[start:], 2)
                self.frameRaw.extend(bytes)
                self.state = FrameDecode.STATE.TAIL
                start += 2
            elif self.state == FrameDecode.STATE.TAIL:
                byte = byteUtil.getByte(data[start:])
                self.frameRaw.append(byte)
                start += 1

                self.state = FrameDecode.STATE.WAIT

                return self.frameRaw, data[start:]

        return None, []


class DataRegionDecode():
    def __init__(self, raw):
        self.raw = raw
        self.afn = packet.AFN(code=self.raw[0])
        self.seq = packet.SEQ(code=self.raw[1])

        self.dataRegion = packet.FrameDataRegion(self.afn, self.seq)

    def decodeDataRegion(self):
        remain = self.raw[2:]

        aixSize = self.auxSize()
        # 剩余字节数大于aux的长度
        while len(remain) > aixSize:
            unit, remain = self.decodeDataUnit(remain)
            logging.debug("recv unit fn:%d pn:%d" % (unit.FN, unit.PN))
            self.dataRegion.addDataUnit(unit)
        if len(remain) < aixSize:
            raise Exception("AUX dataSize error!")
        else:
            aux = self.decodeAUX(remain)
            self.dataRegion.AUX = aux

            return self.dataRegion

    def hasTp(self):
        if self.seq.TpV == 1:
            return True
        else:
            return False

    def hasCounter(self):
        return bool(self.afn.ACD)

    def auxSize(self):
        size = 0
        if self.hasTp():
            size += 6
        if self.hasCounter():
            size += 2

        return size


    def decodeAUX(self, raw):
        tp = None
        counter = None
        if self.hasTp():
            tp = self.decodeTP(raw)

        if self.hasCounter():
            counter = self.decodeCounter(raw)

        aux = packet.AUX(counter, tp)
        return aux

    def decodeTP(self, raw):
        pfc = raw[0]
        time = raw[1:5]
        delayAllow = raw[5]
        tp = packet.TP(pfc, delayAllow, time)
        return tp

    def decodeCounter(self, raw):
        pass

    def decodeDataUnit(self, raw):
        da = raw[0:2]
        dt = raw[2:4]

        unit = packet.DataUnit(da, dt)
        dataSize = getUnitDataSize(self.afn.CMD, unit.FN, raw[4:])
        end = dataSize + 4
        unitData = raw[4:end]
        unit.rawData = unitData

        unit.raw = raw[:end]
        return unit, raw[end:]


def getUnitDataSize(afn, fn, raw):
    try:
        key = "afn_%x" % afn
        sizeDict = _data_unit_size[key]

        key = "f%d" % fn

        if not sizeDict.has_key(key):
            logging.warn("afn:%d ,fn:%d ,unknow size" % (afn, fn))
            return 0
        else:
            size = sizeDict[key]
            if size != -1:
                return size
            else:
                str = "afn%02x_fn%02d_size" % (afn, fn)
                func = eval(str)
                if func:
                    size = func(raw)
                return size
    except:
        return 0


def afn04_fn07_size(raw):
    termCount = raw[6]
    return termCount * 8 + 7


def afn04_fn09_size(raw):
    dayCount = byteUtil.decodeShort(raw[2:4])
    return dayCount * 4 + 4


def afn04_fn13_size(raw):
    count = raw[1]
    return count * 11 + 2


def afn04_fn17_size(raw):
    termNum = raw[0]
    return termNum * 16 + 1


def afn04_fn18_size(raw):
    lampNum = raw[0]
    return lampNum * 6 + 1


def afn04_fn19_size(raw):
    count = raw[1]
    return count * 11 + 2


def afn04_fn20_size(raw):
    return raw[0] + 1


def afn04_fn25_size(raw):
    return raw[0]*3 + 2


def afn04_fn26_size(raw):
    count = raw[0]
    return count * 12 + 2


def afn0a_fn09_size(raw):
    count = raw[0]
    return count * 2 + 2


def afn0a_fn17_size(raw):
    count = raw[0]
    return count * 2 + 1


def afn0a_fn18_size(raw):
    count = raw[0]
    return count * 2 + 1

def afn0a_fn19_size(raw):
    count = raw[0]
    return count * 2 + 1

def afn0a_fn25_size(raw):
    return 2

